package com.fezs.common.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author zhukai
 * @since 2022/8/18
 */
public class SpelUtils {

    /**
     * 用于SpEL表达式解析.
     */
    private static final SpelExpressionParser PARSER = new SpelExpressionParser();

    /**
     * 用于获取方法参数定义名字.
     */
    private static final DefaultParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();

    /**
     * 解析SpEL表达式
     */
    public static String getSpelDefinitionKey(Method method, String[] keys, Object[] parameterValues) {
        EvaluationContext context = buildContext(method, parameterValues);
        List<String> definitionKeyList = new ArrayList<>(keys.length);
        for (String definitionKey : keys) {
            if (StrUtil.isNotEmpty(definitionKey)) {
                Object value = parseExpression(context, definitionKey);
                if (value != null) {
                    String key = value.toString();
                    definitionKeyList.add(key);
                }
            }
        }
        return CollUtil.join(definitionKeyList, StrPool.DOT);
    }

    /**
     * 构建解析的上下文 EvaluationContext
     */
    public static EvaluationContext buildContext(Method method, Object[] parameterValues) {
        return new MethodBasedEvaluationContext(null, method, parameterValues, NAME_DISCOVERER);
    }

    /**
     * 解析 EL 表达式的结果
     */
    public static Object parseExpression(EvaluationContext context, String spelExpression) {
        return PARSER.parseExpression(spelExpression).getValue(context);
    }

    /**
     * 从切面中，单个解析 EL 表达式的结果
     *
     * @param joinPoint  切面点
     * @param spelExpression EL 表达式数组
     * @return 执行界面
     */
    public static Object parseExpression(ProceedingJoinPoint joinPoint, String spelExpression) {
        Map<String, Object> result = parseExpressionList(joinPoint, Collections.singletonList(spelExpression));
        return result.get(spelExpression);
    }

    /**
     * 从切面中，批量解析 EL 表达式的结果
     *
     * @param joinPoint   切面点
     * @param spelExpressionList EL 表达式数组
     * @return 结果，key 为表达式，value 为对应值
     */
    public static Map<String, Object> parseExpressionList(ProceedingJoinPoint joinPoint, List<String> spelExpressionList) {
        // 如果为空，则不进行解析
        if (CollUtil.isEmpty(spelExpressionList)) {
            return MapUtil.newHashMap();
        }

        // 1.构建解析的上下文 EvaluationContext
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Object[] args = joinPoint.getArgs();
        EvaluationContext context = buildContext(method, args);

        // 2.逐个参数解析
        Map<String, Object> result = MapUtil.newHashMap(spelExpressionList.size(), true);
        for (String spelExpression : spelExpressionList) {
            Object value = parseExpression(context, spelExpression);
            result.put(spelExpression, value);
        }
        return result;
    }
}
